package com.mhtool.core.collection;


import com.mhtool.core.exception.Assert;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.cglib.core.CollectionUtils;
import org.springframework.cglib.core.Transformer;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.io.Serializable;
import java.util.*;
import java.util.function.Predicate;


/**
 * @author yin
 * @date 2021/12/27 17:20
 * @since 8.0.0
 */
@UtilityClass
public class IterableUtils {
    public static <T> boolean some(Iterable<T> iterable, Predicate<? super T> predicate) {
        if (null == iterable) {
            return false;
        }
        Objects.requireNonNull(predicate);
        for (T next : iterable) {
            if (predicate.test(next)) {
                return true;
            }
        }
        return false;
    }
    public static <T> T findFirst(@Nullable Iterable<T> iterable, @NotNull Predicate<? super T> predicate) {
        if (null == iterable) {
            return null;
        }

        Assert.notNull(predicate, "predicate");

        for (T next : iterable) {
            if (predicate.test(next)) {
                return next;
            }
        }
        return null;
    }

    /**
     * @see CollectionUtils#bucket(Collection, Transformer)
     */
    public static <K extends Serializable, T> MultiValueMap<K, T> bucket(Iterable<T> iterable, @NotNull Converter<T, K> converter) {
        Assert.notNull(converter,"converter");
        Iterator<T> it;
        if (null == iterable || !(it = iterable.iterator()).hasNext()) {
            return new LinkedMultiValueMap<>(0);
        }
        MultiValueMap<K, T> map = new LinkedMultiValueMap<>();
        T t; // 节约内存
        while (it.hasNext()) {
            t = it.next();
            map.add(converter.convert(t), t);
        }
        return map;
    }

    /**
     * 按唯一键分组
     */
    public static <K extends Serializable, T> Map<K, T> bucketSingle(Iterable<T> iterable, Converter<T, K> converter) {
        Iterator<T> it;
        if (null == iterable || !(it = iterable.iterator()).hasNext()) {
            return Collections.emptyMap();
        }
        Map<K, T> map = iterable instanceof Collection ? new LinkedHashMap<>(((Collection<T>) iterable).size()) :  new HashMap<>();
        T t; // 节约内存
        while (it.hasNext()) {
            t = it.next();
            map.put(converter.convert(t), t);
        }
        return map;
    }

    public static <E> List<E> iterable2List(final Iterable<? extends E> iterable) {
        if (null == iterable)
            return new ArrayList<>(0);
        List<E> result = new ArrayList<>();
        for (E e : iterable) {
            result.add(e);
        }
        return result;
    }
}